AWS Amplify+Angular6+Cognitoでログインページを作ってみる ~フロントエンド編②~
どうも!大阪オフィスの西村祐二です。
本ブログは下記の続きになります。
- AWS Amplify+Angular6+Cognitoでログインページを作ってみる ~バックエンド編~
- AWS Amplify+Angular6+Cognitoでログインページを作ってみる ~フロントエンド編①~
- 今回:AWS Amplify+Angular6+Cognitoでログインページを作ってみる ~フロントエンド編②~
- AWS Amplify+Angular6+Cognitoでログインページを作ってみる ~UI編~
ゴールとして下記動画のようなサイトを構築していきます。
前回、Angular6とAWS-Amplify
を使って、設定周りと、外部と通信するところのロジック部分の実装を行いました。
今回は、画面を構成するコンポーネントの実装を行っていきます。
コンポーネントとしては下記を作成していきます。
- ログイン画面
- サインアップ画面
- ペット情報取得、一覧表示画面(ホーム画面に配置)
- ホーム画面
ログイン画面
LoginComponent
ログイン画面のコンポーネントを作成します。
$ ng g component component/login
import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { Router } from '@angular/router'; import { AuthService } from './../../auth/auth.service'; @Component({ selector: 'app-login', templateUrl: './login.component.html', styleUrls: ['./login.component.css'] }) export class LoginComponent implements OnInit { public loginForm: FormGroup; constructor( private fb: FormBuilder, private router: Router, private auth: AuthService ) {} ngOnInit() { this.initForm(); } initForm() { this.loginForm = this.fb.group({ email: ['', Validators.required], password: ['', Validators.required] }); } onSubmitLogin(value: any) { const email = value.email, password = value.password; this.auth.signIn(email, password).subscribe( result => { this.router.navigate(['/']); }, error => { console.log(error); } ); } }
- initForm()
- メールアドレス、パスワードを入力するための入力フォームの設定を行っています。初期値、バリデーションなども行うことができます。今回、
required
としているので、入力必須としています。
- メールアドレス、パスワードを入力するための入力フォームの設定を行っています。初期値、バリデーションなども行うことができます。今回、
- onSubmitLogin(value: any)
- ログインフォームがサブミットされる際のイベントハンドラです。
AuthService
のsignIn()
メソッドの結果を受けて、ログインに成功したら['/']
に遷移する設定となっています。が、ルーティングの設定(app-routing.module.ts
)でhome
へリダイレクトされます。
- ログインフォームがサブミットされる際のイベントハンドラです。
サインアップ画面
SignupComponent
サインアップ(登録)画面のコンポーネントを作成します。 このページでは、登録情報の入力と、確認コードの検証を行います。
$ ng g component component/signup
import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { Router } from '@angular/router'; import { AuthService } from './../../auth/auth.service'; @Component({ selector: 'app-signup', templateUrl: './signup.component.html', styleUrls: ['./signup.component.css'] }) export class SignupComponent implements OnInit { public signupForm: FormGroup; public confirmationForm: FormGroup; public successfullySignup: boolean; constructor( private fb: FormBuilder, private router: Router, private auth: AuthService ) {} ngOnInit() { this.initForm(); } initForm() { this.signupForm = this.fb.group({ email: ['', Validators.required], password: ['', Validators.required] }); this.confirmationForm = this.fb.group({ email: ['', Validators.required], confirmationCode: ['', Validators.required] }); } onSubmitSignup(value: any) { const email = value.email, password = value.password; this.auth.signUp(email, password).subscribe( result => { this.successfullySignup = true; }, error => { console.log(error); } ); } onSubmitConfirmation(value: any) { const email = value.email, confirmationCode = value.confirmationCode; this.auth.confirmSignUp(email, confirmationCode).subscribe( result => { this.auth.signIn(email, this.auth.password).subscribe( () => { this.router.navigate(['/']); }, error => { console.log(error); this.router.navigate(['/login']); } ); }, error => { console.log(error); } ); } }
- onSubmitSignup()
- サインアップフォームがサブミットされる際のイベントハンドラ。
AuthService
のsignUp()
メソッドの結果、サインアップに成功したら、successfullySignup
フラグをtrue
にし、検証コードの入力フォームを表示しています。
- サインアップフォームがサブミットされる際のイベントハンドラ。
- onSubmitConfirmation()
- 検証コードの入力フォームがサブミットされる際のイベントハンドラ。
AuthService
のconfirmSignUp()
メソッドの結果、サインアップに成功したらログインを行い、home画面へ遷移します。
- 検証コードの入力フォームがサブミットされる際のイベントハンドラ。
ペット情報取得、一覧表示画面
PetComponent
ペット情報取得、一覧表示画面を作成します。 このページでは、APIを叩いてペット情報を取得、取得した情報を画面に表示します。
petクラスを作成し、APIから取得したデータをとる変数petsData
にPet型として設定します。
$ ng g class component/pet
export class Pet { id: number; type: string; price: number; }
次にのコンポーネントを作成します。
$ ng g component component/pet
import { Component, OnInit } from '@angular/core'; import { PetService } from './../../pet/pet.service'; import { AuthService } from './../../auth/auth.service'; import { Pet } from './pet'; @Component({ selector: 'app-pet', templateUrl: './pet.component.html', styleUrls: ['./pet.component.css'] }) export class PetComponent implements OnInit { private token: string; petsData: Pet[]; constructor(private petService: PetService, private auth: AuthService) {} ngOnInit() { this.token = this.auth.getIdToken(); } Pet(): void { this.petService.getPets(this.token).subscribe(result => { this.petsData = result; console.log(result); }); } }
- this.token = this.auth.getIdToken();
- HTTPリクエストの際にトークンをヘッダに付与するために
auth.getIdToken()
から取得しています。
- HTTPリクエストの際にトークンをヘッダに付与するために
- Pet()
- HTTPリクエストするためボタンをクリックしたときのイベントハンドラ。
petService.getPets(this.token)
メソッドを実行し、その結果をpetsData
に格納します。
- HTTPリクエストするためボタンをクリックしたときのイベントハンドラ。
ホーム画面
HomeComponent
ログイン済みのユーザーのみが閲覧出来るページのコンポーネントを作成します。
$ ng g component component/home
import { Component, OnInit } from '@angular/core'; import { AuthService } from './../../auth/auth.service'; @Component({ selector: 'app-home', templateUrl: './home.component.html', styleUrls: ['./home.component.css'] }) export class HomeComponent implements OnInit { username: String; constructor(private auth: AuthService) {} ngOnInit() { this.getData(); } getData(): void { this.auth.getData().subscribe( result => { console.log(result); this.username = result.username; }, error => { console.log(error); } ); } }
- getData()
- ログイン時にHomeの画面上にログインしたユーザ名を表示するために、
auth.getData()
メソッドを実行し、その結果をusername
に追加しています。
- ログイン時にHomeの画面上にログインしたユーザ名を表示するために、
ナビバー
AppComponent
AppComponentには各ページ共通で表示するナビゲーションを配置しました。
import { Component, OnInit, OnDestroy, AfterViewChecked, ChangeDetectorRef } from '@angular/core'; import { Subscription } from 'rxjs'; import { AuthService } from './auth/auth.service'; import { environment } from '../environments/environment'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit, OnDestroy, AfterViewChecked { subscription: Subscription; username: String; loggedIn: boolean; constructor(public auth: AuthService, private cdr: ChangeDetectorRef) { this.username = localStorage.getItem( environment.localstorageBaseKey + 'LastAuthUser' ); } ngOnInit() { this.subscription = this.auth.isAuthenticated().subscribe(result => { this.loggedIn = result; }); } ngAfterViewChecked() { this.username = localStorage.getItem( environment.localstorageBaseKey + 'LastAuthUser' ); this.cdr.detectChanges(); } ngOnDestroy() { this.subscription.unsubscribe(); } onClickLogout() { this.auth.signOut(); } }
- ナビゲーションのログイン・ログアウト
- AuthServiceのloggedInSubjectをasyncパイプで受け取って、表示する内容を変更しています。
- ngOnInit()
- ページがリロードされた際にログイン状態を再取得するためにAuthServiceのisAuthenticated()メソッドを呼び出しています。
- ngAfterViewChecked()
- 子コンポーネントの読み込みが完了したあとに実行されるメソッドです。ローカルストレージからusernameを取得します。だた、現状
ExpressionChangedAfterItHasBeenCheckedError
がでます。今度修正したいと思います。 - =>
ChangeDetectorRef
を使うことでエラーを回避できました。
- 子コンポーネントの読み込みが完了したあとに実行されるメソッドです。ローカルストレージからusernameを取得します。だた、現状
- onClickLogout()
- ログインボタンが押された際のイベントハンドラ。
AppModule
最終的なsrc/app/app.module.ts
は次のようになりました。
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { HttpClientModule } from '@angular/common/http'; import { LoginComponent } from './component/login/login.component'; import { SignupComponent } from './component/signup/signup.component'; import { HomeComponent } from './component/home/home.component'; import { PetComponent } from './component/pet/pet.component'; @NgModule({ declarations: [ AppComponent, LoginComponent, SignupComponent, HomeComponent, PetComponent ], imports: [ BrowserModule, AppRoutingModule, FormsModule, ReactiveFormsModule, HttpClientModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule {}
さいごに
いかがだったでしょうか。
画面を構成するコンポーネント部分の実装を行いました。
次はBootstrap4を使ってスタイリングをやっていきます。